package com.example.mychat.service.impl;

import com.example.mychat.entity.config.AppConfig;
import com.example.mychat.entity.constants.Constants;
import com.example.mychat.entity.dto.TokenUserInfoDto;
import com.example.mychat.entity.dto.UserContactSearchResultDto;
import com.example.mychat.entity.enums.*;
import com.example.mychat.entity.po.*;
import com.example.mychat.entity.query.*;
import com.example.mychat.entity.vo.PaginationResultVO;
import com.example.mychat.entity.vo.UserInfoVO;
import com.example.mychat.exception.BusinessException;
import com.example.mychat.mapper.UserContactMapper;
import com.example.mychat.mapper.UserInfoBeautyMapper;
import com.example.mychat.mapper.UserInfoMapper;

import com.example.mychat.redis.RedisComponent;
import com.example.mychat.redis.RedisUtils;
import com.example.mychat.service.ChatSessionUserService;
import com.example.mychat.service.UserContactService;
import com.example.mychat.service.UserInfoService;
import com.example.mychat.utils.CopyTools;
import com.example.mychat.utils.DateUtil;
import com.example.mychat.utils.StringTools;

import com.example.mychat.webSocket.MessageHandler;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.example.mychat.entity.enums.UserContactStatusEnum.BLACKLIST;
import static com.example.mychat.entity.enums.UserContactStatusEnum.DEL_BE;


/**
 * 业务接口实现
 */
@Slf4j
@Service("userInfoService")
public class UserInfoServiceImpl implements UserInfoService {

    @Resource
    private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

    @Resource
    private AppConfig appConfig;

    @Resource
    private UserContactMapper<UserContact,UserContactQuery> userContactMapper;

    @Resource
    private UserInfoBeautyMapper<UserInfoBeauty, UserInfoBeautyQuery> userInfoBeautyMapper;

    @Resource
    private RedisComponent redisComponent;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private UserContactService userContactService;

//    @Resource
//    private MessageHandler messageHandler;

    @Resource
    private ChatSessionUserService chatSessionUserService;
    /**
     * 根据条件查询列表
     */
    @Override
    public List<UserInfo> findListByParam(UserInfoQuery param) {
        return this.userInfoMapper.selectList(param);
    }

    /**
     * 根据条件查询列表
     */
    @Override
    public Integer findCountByParam(UserInfoQuery param) {
        return this.userInfoMapper.selectCount(param);
    }

    /**
     * 分页查询方法
     */
    @Override
    public PaginationResultVO<UserInfo> findListByPage(UserInfoQuery param) {
        int count = this.findCountByParam(param);
        int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

        SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
        param.setSimplePage(page);
        List<UserInfo> list = this.findListByParam(param);
        PaginationResultVO<UserInfo> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
        return result;
    }

    /**
     * 新增
     */
    @Override
    public Integer add(UserInfo bean) {
        return this.userInfoMapper.insert(bean);
    }

    /**
     * 批量新增
     */
    @Override
    public Integer addBatch(List<UserInfo> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.userInfoMapper.insertBatch(listBean);
    }

    /**
     * 批量新增或者修改
     */
    @Override
    public Integer addOrUpdateBatch(List<UserInfo> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.userInfoMapper.insertOrUpdateBatch(listBean);
    }

    /**
     * 多条件更新
     */
    @Override
    public Integer updateByParam(UserInfo bean, UserInfoQuery param) {
        StringTools.checkParam(param);
        return this.userInfoMapper.updateByParam(bean, param);
    }

    /**
     * 多条件删除
     */
    @Override
    public Integer deleteByParam(UserInfoQuery param) {
        StringTools.checkParam(param);
        return this.userInfoMapper.deleteByParam(param);
    }

    /**
     * 根据UserId获取对象
     */
    @Override
    public UserInfo getUserInfoByUserId(String userId) {
        return this.userInfoMapper.selectByUserId(userId);
    }

    /**
     * 根据UserId修改
     */
    @Override
    public Integer updateUserInfoByUserId(UserInfo bean, String userId) {
        return this.userInfoMapper.updateByUserId(bean, userId);
    }

    /**
     * 根据UserId删除
     */
    @Override
    public Integer deleteUserInfoByUserId(String userId) {
        return this.userInfoMapper.deleteByUserId(userId);
    }

    /**
     * 根据Email获取对象
     */
    @Override
    public UserInfo getUserInfoByEmail(String email) {
        return this.userInfoMapper.selectByEmail(email);
    }

    /**
     * 根据Email修改
     */
    @Override
    public Integer updateUserInfoByEmail(UserInfo bean, String email) {
        return this.userInfoMapper.updateByEmail(bean, email);
    }

    /**
     * 根据Email删除
     */
    @Override
    public Integer deleteUserInfoByEmail(String email) {
        return this.userInfoMapper.deleteByEmail(email);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void register(String email, String nickName, String password) {
        UserInfo userInfo = userInfoMapper.selectByEmail(email);
        if (userInfo != null){
            throw new BusinessException(ResponseCodeEnum.CODE_601);
        }
        String userId = StringTools.getUserId();
        UserInfoBeauty beauty = userInfoBeautyMapper.selectByEmail(email);
        Boolean userBeautyAccount = beauty != null && BeautyAccountStatusEnum.NO_USE.getStatus().equals(beauty.getStatus());
        if (userBeautyAccount){
            userId = beauty.getUserId();
        }
        Date curDate = new Date();

        UserInfo userInfo1 = new UserInfo();
        userInfo1.setUserId(userId);
        userInfo1.setEmail(email);
        userInfo1.setNickName(nickName);
        userInfo1.setPassword(StringTools.encodeByMD5(password));
        userInfo1.setCreateTime(curDate);
        userInfo1.setStatus(UserStatusEnum.ENABLE.getStatus());
        userInfo1.setLastOffTime(curDate.getTime());
        userInfo1.setJoinType(JoinTypeEnum.APPLY.getType());
        userInfoMapper.insert(userInfo1);

        if (userBeautyAccount){
            UserInfoBeauty userInfoBeauty = new UserInfoBeauty();
            userInfoBeauty.setStatus(UserStatusEnum.ENABLE.getStatus());
            userInfoBeautyMapper.updateByEmail(userInfoBeauty,email);
        }

        //添加机器人及欢迎消息
        userContactService.addRobot4Contact(userId);

    }

    @Override
    public UserInfoVO login(String email, String password) {
        UserInfo userInfo = userInfoMapper.selectByEmail(email);
        if (userInfo == null){
            throw new BusinessException("账号或密码错误");
        }
        if (!userInfo.getPassword().equals(password) || userInfo.getStatus().equals(UserStatusEnum.DISABLE.getStatus())) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        UserContactQuery query = new UserContactQuery();
        query.setStatus(UserContactStatusEnum.FRIEND.getStatus());
        query.setUserId(userInfo.getUserId());
        List<UserContact> userContactList = userContactMapper.selectList(query);
        List<String> contactList = userContactList.stream().map(UserContact::getContactId).collect(Collectors.toList());
//        redisComponent.saveMyContact(userInfo.getUserId(),contactList);
        insert(userInfo.getUserId(),contactList);
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto(userInfo);

        Long lastHeartBeat = redisComponent.getUserHeartBeat(userInfo.getUserId());
        if (lastHeartBeat != null){
            throw new BusinessException("此账号已经在别处登录，清退出后再登录");
        }
        userInfo.setLastLoginTime(new Date());
        //保存登录信息到redis中
        String token = StringTools.encodeByMD5(tokenUserInfoDto.getUserId() + StringTools.getRandomString(Constants.LENGTH_20));
        tokenUserInfoDto.setToken(token);
        redisComponent.saveTokenUserInfoDto(tokenUserInfoDto);

        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(userInfo,userInfoVO);
        userInfoVO.setToken(token);
        userInfoVO.setAdmin(tokenUserInfoDto.getAdmin());

        return userInfoVO;
    }

    @Override
    public void updateUserInfo(UserInfo userInfo, MultipartFile avatarFile, MultipartFile avatarCover) throws IOException {

    }

    @Override
    public void updateUserStatus(Integer status, String userId) {
        UserStatusEnum userStatusEnum = UserStatusEnum.getByStatus(status);
        if (userStatusEnum == null) {
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        UserInfo updateInfo = new UserInfo();
        updateInfo.setStatus(userStatusEnum.getStatus());
        userInfoMapper.updateByUserId(updateInfo, userId);
    }

    @Override
    public void forceOffLine(String userId) {

    }

    private TokenUserInfoDto getTokenUserInfoDto(UserInfo userInfo){
        TokenUserInfoDto dto = new TokenUserInfoDto();
        dto.setUserId(userInfo.getUserId());
        dto.setNickName(userInfo.getNickName());
        String adminEmails = appConfig.getAdminEmails();
        String[] split = adminEmails.split(",");
        if (!StringTools.isEmpty(adminEmails) && ArrayUtils.contains(split,userInfo.getEmail())){
            dto.setAdmin(true);
        }else {
            dto.setAdmin(false);
        }
        return dto;
    }

    @Override
    public UserInfoVO getContactInfo(TokenUserInfoDto tokenUserInfo, String contactId) {
        UserInfo userInfo = userInfoMapper.selectByUserId(contactId);
        UserInfoVO userInfoVO = new UserInfoVO();
        BeanUtils.copyProperties(userInfo,userInfoVO);

        return userInfoVO;

    }

    @Override
    public void changeContact(TokenUserInfoDto tokenUserInfo, String contactId, Integer status) {
        String userId = tokenUserInfo.getUserId();
        //自己的好友
        UserContact myself = userContactMapper.selectByUserIdAndContactId(userId, contactId);

        if (myself == null){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        UserContactStatusEnum statusEnum = UserContactStatusEnum.getByStatus(myself.getStatus());
        if (!myself.getStatus().equals(UserContactStatusEnum.FRIEND.getStatus())){
            switch (statusEnum) {
                case BLACKLIST_BE:
                    throw new BusinessException("您已被对方拉黑，无法操作");
                case DEL_BE:
                    throw new BusinessException("您已被对方删除，无法操作");
                case NOT_FRIEND:
                    throw new BusinessException("您不是对方好友，无法操作");
            }
        }
        UserContact hiself = userContactMapper.selectByUserIdAndContactId(contactId,userId);
        Date curDate = new Date();
        hiself.setLastUpdateTime(curDate);
        myself.setLastUpdateTime(curDate);
        if (status.equals(UserContactStatusEnum.DEL.getStatus())){
            hiself.setStatus(DEL_BE.getStatus());
        }else if (status.equals(UserContactStatusEnum.BLACKLIST.getStatus())){
            hiself.setStatus(BLACKLIST.getStatus());
        }
        myself.setStatus(status);
        List<UserContact> userContactList = new ArrayList<>();
        userContactList.add(myself);
        userContactList.add(hiself);
        Integer i = userContactMapper.insertOrUpdateBatch(userContactList);
        if (i < 2){
            throw new BusinessException("错误操作");
        }

        redisComponent.delete1UserContact(userId,contactId);
        redisComponent.delete1UserContact(contactId,userId);
    }

    @Override
    public void saveUserInfo(UserInfo userInfo, String userId,MultipartFile avatarFile,
                             MultipartFile avatarCover) {
        UserInfo user = userInfoMapper.selectByUserId(userId);
        if (user == null){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        userInfo.setUserId(userId);
        userInfo.setPassword(null);
        userInfo.setStatus(null);
        userInfo.setCreateTime(null);
        userInfo.setLastLoginTime(null);
        userInfo.setEmail(null);
        Integer i = userInfoMapper.updateByUserId(userInfo, userId);
        if (i == 0){
            throw new BusinessException(ResponseCodeEnum.CODE_500);
        }
        if (avatarFile != null) {
        String targetPath = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE + Constants.FILE_FOLDER_AVATAR_NAME;
        File targetFile = new File(targetPath);
        if (targetFile.exists()){
            targetFile.mkdirs();
        }
        String path = targetFile.getPath() + "/" + userId;

            try {
                avatarFile.transferTo(new File(path + Constants.IMAGE_SUFFIX));
                avatarCover.transferTo(new File(path + Constants.COVER_IMAGE_SUFFIX));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        String updateName = null;
        if (user.getNickName().equals(userInfo.getNickName())){
            return;
        }
        updateName = userInfo.getNickName();
        TokenUserInfoDto tokenUserInfoDto = redisComponent.getTokenUserInfoByUserId(userId);
        redisComponent.saveTokenUserInfoDto(tokenUserInfoDto);
        chatSessionUserService.updateRedundanceInfo(updateName,userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insert(String userId, List<String> contactList) {
        redisComponent.saveMyContact(userId,contactList);
    }

    @Override
    public void commitTcc(BusinessActionContext context) {
        log.info("提交redis操作");
    }

    @Override
    public void cancel(BusinessActionContext context) {
        redisComponent.delete1UserContact((String) context.getActionContext("userId"),(String) context.getActionContext("contactId"));
    }
}